package mqtt

import (
	"encoding/json"
	"fmt"
	"gin-base/base/config"
	"gin-base/common/middleware/token"
	"gin-base/common/utils"
	MQTT "github.com/eclipse/paho.mqtt.golang"
	"os"
)

var MQTTServer string
var MQTTUsername string
var MQTTPassword string

const QOS_ALMOST_ONE = 0
const QOS_ATLEAST_ONE = 1
const QOS_EXACTLY_ONE = 2

func init() {

	if config.Ini.String("app.mode") == "prod" {
		MQTTServer = config.Ini.String("mqtt.server")
		MQTTUsername = config.Ini.String("mqtt.username")
		MQTTPassword = config.Ini.String("mqtt.password")
	} else {
		MQTTServer = config.Ini.String("mqtt.server_dev")
		MQTTUsername = config.Ini.String("mqtt.username_dev")
		MQTTPassword = config.Ini.String("mqtt.password_dev")
	}
}

//连接事件
var onConnect = func(client MQTT.Client) {
	println("connect")
}

//断开链接事件
var onConnectLost = func(client MQTT.Client, err error) {
	println("close connect: " + err.Error())

	//重新连接
	if token := client.Connect(); token.Wait() && token.Error() != nil {
		panic(token.Error())
	}

	//重新订阅 token 创建消息
	SubscribeTokenCreate(client)
}

//启动mqtt监听模块
func GetMqttCon() {
	//初始化mqtt
	con := initMqtt()

	//订阅 token 创建消息
	SubscribeTokenCreate(*con)

	//订阅 密码重置消息
	SubscribePasswordReset(*con)
}

func initMqtt() *MQTT.Client {
	opts := MQTT.NewClientOptions().AddBroker(MQTTServer)
	opts.SetClientID("PULSE:" + utils.Srand(32, 2))
	opts.SetUsername(MQTTUsername)
	opts.SetPassword(MQTTPassword)
	opts.WillEnabled = true
	opts.WillQos = QOS_EXACTLY_ONE

	//设置断开连接事件
	opts.SetConnectionLostHandler(onConnectLost)

	//create and start a client using the above ClientOptions
	con := MQTT.NewClient(opts)

	if token := con.Connect(); token.Wait() && token.Error() != nil {
		panic(token.Error())
	} else {
		fmt.Println("MQTT: 连接成功")
	}

	return &con
}

//订阅 token 生成事件
func SubscribeTokenCreate(client MQTT.Client) {
	if token := client.Subscribe(MQTTUsername+"/token/create", QOS_EXACTLY_ONE, createTokenHandle); token.Wait() && token.Error() != nil {
		fmt.Println(token.Error())
		os.Exit(1)
	}
}

//处理 token 生成事件
var createTokenHandle MQTT.MessageHandler = func(client MQTT.Client, msg MQTT.Message) {
	fmt.Printf("MSG: %s\n", msg.Payload())

	//消息解析
	var data interface{}
	json.Unmarshal(msg.Payload(), &data)
	data_map := data.(map[string]interface{})

	content_str, exist := data_map["content"]
	if !exist {
		fmt.Printf("消息结构异常：content")
	}

	//创建本地token
	token_map := content_str.(map[string]interface{})
	tokenContent := new(token.Token)
	tokenContent.Value = token_map["access_token"].(string)
	tokenContent.UnionId = token_map["union_id"].(string)
	tokenContent.Expire = token_map["expires"].(string)

	if !tokenContent.Create() {
		//log
	} else {
		//创建本地token unionId关联
		if !tokenContent.RelateUnionId() {
			//log
		}
	}
}

//订阅 密码重置消息
func SubscribePasswordReset(client MQTT.Client) {
	if token := client.Subscribe(MQTTUsername+"/password-reset", QOS_EXACTLY_ONE, resetPasswordHandle); token.Wait() && token.Error() != nil {
		fmt.Println(token.Error())
		os.Exit(1)
	}
}

//处理 密码重置消息
var resetPasswordHandle MQTT.MessageHandler = func(client MQTT.Client, msg MQTT.Message) {
	fmt.Printf("MSG: %s\n", msg.Payload())

	//消息解析
	var data interface{}
	json.Unmarshal(msg.Payload(), &data)
	data_map := data.(map[string]interface{})

	content_str, exist := data_map["content"]
	if !exist {
		fmt.Printf("消息结构异常：content")
	}

	//重置该用户下的token
	token_map := content_str.(map[string]interface{})
	token.DeleteTokenByUnionId(token_map["union_id"].(string))
}
